/*
 * Copyright (c) 2017-2019, Lindenis Tech. Ltd.
 * All rights reserved.
 *
 * File:
 *
 * Description:
 *
 * Author:
 *      xiaoshujun@lindeni.com
 *
 * Create Date:
 *      2019/11/18
 *
 * History:
 *
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
#include <time.h>

#ifdef WIN32
#include <windows.h>
#endif
#ifdef MELIS_OS
#include "clock_time.h"
#endif

#include "osal_log.h"
#include "osal_common.h"
#ifdef LOG_TYPE_ELOG
#include "elog.h"
#endif

static char g_log_inited = 0;
char g_log_level = LOG_LVL_DEBUG;

static char g_log_level_char[LOG_LVL_SILENT] = {'F', 'E', 'W', 'I', 'D', 'V'};

/**
 * CSI(Control Sequence Introducer/Initiator) sign
 * more information on https://en.wikipedia.org/wiki/ANSI_escape_code
 */
#define CSI_START                       "\033["
#define CSI_END                         "\033[0m"
/* output log front color 30+[0, 7]*/
#define CSI_F_BLACK                     "30;"
#define CSI_F_RED                       "31;"
#define CSI_F_GREEN                     "32;"
#define CSI_F_YELLOW                    "33;"
#define CSI_F_BLUE                      "34;"
#define CSI_F_MAGENTA                   "35;"
#define CSI_F_CYAN                      "36;"
#define CSI_F_WHITE                     "37;"
/* output log background color  40+[0, 7]*/
#define CSI_B_NULL
#define CSI_B_BLACK                     "40;"
#define CSI_B_RED                       "41;"
#define CSI_B_GREEN                     "42;"
#define CSI_B_YELLOW                    "43;"
#define CSI_B_BLUE                      "44;"
#define CSI_B_MAGENTA                   "45;"
#define CSI_B_CYAN                      "46;"
#define CSI_B_WHITE                     "47;"
/* output log fonts style */
#define CSI_S_BOLD                      "1m"
#define CSI_S_UNDERLINE                 "4m"
#define CSI_S_BLINK                     "5m"
#define CSI_S_NORMAL                    "22m"

/* color output info */
static const char * g_color_output_info[LOG_LVL_SILENT] = {
    [LOG_LVL_FATAL]     = (CSI_F_MAGENTA CSI_S_NORMAL),
    [LOG_LVL_ERROR]     = (CSI_F_RED CSI_S_NORMAL),
    [LOG_LVL_WARN]      = (CSI_F_YELLOW CSI_S_NORMAL),
    [LOG_LVL_INFO]      = (CSI_F_GREEN CSI_S_NORMAL),
    [LOG_LVL_DEBUG]     = (CSI_F_WHITE CSI_S_NORMAL),
    [LOG_LVL_VERBOSE]   = (CSI_F_WHITE CSI_S_NORMAL),
    };

#ifdef LOG_TYPE_ANDROID
#include <android/log.h>
static char g_log_level_android[LOG_LVL_SILENT] = {
    ANDROID_LOG_FATAL,
    ANDROID_LOG_ERROR,
    ANDROID_LOG_WARN,
    ANDROID_LOG_INFO,
    ANDROID_LOG_DEBUG,
    ANDROID_LOG_VERBOSE
    };
#endif

#if USE_UART_DEBUG
   #define DEBUG_UART_PORT  "/dev/ttyS0"
#endif

static int ld_uart_log(const char *fmt, ...) {
   int ret;
   va_list ap;
   va_start(ap, fmt);
#if USE_UART_DEBUG
   FILE *tty_out = fopen(DEBUG_UART_PORT, "w+");
   if(NULL != tty_out)  {
          ret = vfprintf(tty_out, fmt, ap);
          fclose(tty_out);
          tty_out = NULL;
   }
   else {
           ret = vfprintf(stdout, fmt, ap);
   }
#else
   ret = vfprintf(stdout, fmt, ap);
#endif
   va_end(ap);
   return ret;
}

#ifdef LOG_TYPE_ELOG
extern void elog_set_cfg(char * file_name, size_t max_size, int max_rotate);
void ld_log_init(char * file_name, size_t max_size, int max_rotate)
{
    if (g_log_inited)
    {
        return;
    }
    g_log_inited = 1;
    /* close printf buffer */
    setbuf(stdout, NULL);
    /* initialize EasyLogger */
    elog_set_cfg(file_name, max_size, max_rotate);
    elog_init();
    int log_fmt = ELOG_FMT_ALL & ~ELOG_FMT_TAG & ~ELOG_FMT_FUNC & ~ELOG_FMT_P_INFO & ~ELOG_FMT_T_INFO;
    /* set EasyLogger log format */
    elog_set_fmt(ELOG_LVL_ASSERT, log_fmt);
    elog_set_fmt(ELOG_LVL_ERROR, log_fmt);
    elog_set_fmt(ELOG_LVL_WARN, log_fmt);
    elog_set_fmt(ELOG_LVL_INFO, log_fmt);
    elog_set_fmt(ELOG_LVL_DEBUG, log_fmt);
    elog_set_fmt(ELOG_LVL_VERBOSE, log_fmt);
#ifdef ELOG_COLOR_ENABLE
    elog_set_text_color_enabled(true);
#endif
    /* start EasyLogger */
    elog_start();
}
#endif

#define LOG_BUF_SIZE 1024
void lind_log_output(unsigned char level, const char *tag, const char *file, const char *func,
        const long line, const char *format, ...)
{
    if (level > g_log_level) {
        return;
    }

    va_list ap;
    char buf[LOG_BUF_SIZE];

    va_start(ap, format);
    vsnprintf(buf, LOG_BUF_SIZE, format, ap);
    va_end(ap);

#ifdef LOG_TYPE_ELOG
    elog_output(level, tag, file, func, line, buf);
#elif (defined LOG_TYPE_ANDROID)
    __android_log_print(g_log_level_android[level], tag, buf);
#elif (defined LOG_TYPE_WIN32)
    char __strTemp[1024];
    sprintf(__strTemp, CSI_START"%s%c/[%lld] <%s:%ld>: %s"CSI_END"\n",
        g_color_output_info[level], g_log_level_char[level],
        get_tick_ms(), file, line, buf);
    OutputDebugString(__strTemp);
#elif (defined LOG_TYPE_PRINTF)
    printf(CSI_START"%s%c/[%lld] <%s:%ld>: %s"CSI_END"\n",
        g_color_output_info[level], g_log_level_char[level],
        get_tick_ms(), file, line, buf);
#endif

}

